'''
Created on Nov 14, 2011

@author: Victor Bos
'''
import Tkinter
import ToolTip

import graphics
import utils
import Action

HIGHLIGHT_colour="yellow"
UNIT_TAG = "unit"
UNIT_MOVE_TAG = "unit_move"

def ctt(canvas, **kw):
    ToolTip.CanvasToolTip(canvas, **kw)

class CanvasUnit:

    def __init__(self, board, unit, unittag=UNIT_TAG, bindevents=True):
        self.board = board
        self.canvas = board.map_canvas
        self.unit = unit
        self.bbox_cid = None
        self.pic_cid = None
        self.drag_pic_cid = None
        self.unittag = unittag
        self.mytag = utils.tag_for_name(unit.name)
        self.bindevents = bindevents

    def compute_cvs_xy(self, xy):
        return self.board.compute_cvs_xy(xy)
    
    def compute_real_xy(self, xy):
        return self.board.compute_real_xy(xy)
    
    def draw(self):
        unit = self.unit
        fc, bc = unit.colour, unit.bgcolour
        cx, cy = self.compute_cvs_xy(unit.last_move_xy())
        if self.pic_cid is None:
            tags = (self.mytag, self.unittag)
            self.pic_cid = self.board.put_unit_on_canvas(
                unit, 
                cx,
                cy,
                tags)
            self.bind_events_on_unit()
        else:
            self.undraw_bbox()
            self.delete_move_arrows()
            old_cx, old_cy = self.canvas.coords(self.pic_cid)
            self.canvas.coords(self.pic_cid, cx, cy)
            self.board.update_stack_number_at(old_cx, old_cy)

        cx, cy = self.snap_to_other_xy()
        self.canvas.coords(self.pic_cid, cx, cy)
        self.board.update_stack_number_at(cx, cy)
        self.draw_bbox()
        self.draw_all_move_arrows()

    def bbox(self):
        if self.pic_cid is not None:
            return self.canvas.bbox(self.pic_cid)
        return None

    def undraw(self):
        unit = self.unit
        if self.pic_cid is not None:
            cx, cy = self.canvas.coords(self.pic_cid)
            self.board.remove_unit_from_canvas(unit)
            self.pic_cid = None
            self.board.update_stack_number_at(cx, cy)
        
    def unit_bbox_tag(self, cid=None):
        if cid is None:
            cid = self.pic_cid
        return "bbox-%d" % cid
        
    def draw_bbox(self):
        bbox = self.bbox()
        colour = "black"
        width = 1
        tags = (self.mytag, self.unittag, self.unit_bbox_tag(self.pic_cid))
        self.bbox_cid = self.canvas.create_rectangle(
            bbox,
            outline = colour,
            width = width,
            tags=tags)
        
    def undraw_bbox(self):
        self.canvas.delete(self.unit_bbox_tag(self.pic_cid))
        self.bbox_cid = None

    def draw_move_arrow(self, idx0, idx1, colour="white", width=1):
        unit = self.unit
        if idx0>idx1:
            idx0, idx1 = idx1, idx0
        if len(unit.move_dest)>idx1:
            x0, y0 = self.board.snap_pos(
                self.compute_cvs_xy(unit.move_dest[idx0]))
            x1, y1 = self.board.snap_pos(
                self.compute_cvs_xy(unit.move_dest[idx1]))
            tags = ("move-arrow-%d" % (self.pic_cid), self.mytag, self.unittag, UNIT_MOVE_TAG)
            self.canvas.create_line(
                x0, y0,
                x1, y1,
                arrow=Tkinter.LAST,
                fill=colour,
                width=width,
                tags=tags)

    def draw_all_move_arrows(self, colour="white", width=1):
        unit = self.unit
        for i in range(0, len(unit.move_dest)-1):
            self.draw_move_arrow(i, i+1, colour, width)

    def delete_move_arrows(self):
        self.canvas.delete("move-arrow-%d" % (self.pic_cid,))

    def highlight(self, colour=HIGHLIGHT_colour):
        unit = self.unit
        bbox = self.bbox()
        x0, y0, x1, y1 = bbox
        tags = ("highlight-%d" % self.pic_cid, self.mytag, self.unittag)
        self.canvas.create_rectangle(
            x0-2, y0-2, x1+2, y1+2,
            outline=colour,
            width=3,
            tags=tags)
        if unit.nr_move_dests()>0:
            self.highlight_move()
        
    def unhighlight(self):
        self.unhighlight_move()
        self.canvas.delete("highlight-%d" % self.pic_cid)

    def highlight_move(self):
        self.delete_move_arrows()
        self.draw_all_move_arrows(colour="yellow", width=3)

    def unhighlight_move(self):
        self.delete_move_arrows()
        self.draw_all_move_arrows()

    def bind_events_on_unit(self):
        if not self.bindevents:
            return
        unit = self.unit
        self.canvas.tag_bind(
            self.pic_cid,
            "<Button-3>",
            lambda args: self.show_unit_attrs(args))
        self.canvas.tag_bind(
            self.pic_cid,
            "<ButtonPress-1>",
            lambda e: self.start_drag_unit(e))
        self.canvas.tag_bind(
            self.pic_cid,
            "<ButtonRelease-1>",
            lambda e: self.end_drag_unit(e))
        self.canvas.tag_bind(
            self.pic_cid,
            "<Motion>",
            lambda e: self.drag_unit(e))
        ctt(self.canvas,
            cid=self.pic_cid,
            text="%s\n\n%s" % (self.unit.name, self.unit.get_attr_str()))
        
    def unbind_events_on_unit(self):
        for e in [
            "<Button-3>",            
            "<ButtonPress-1>",
            "<ButtonRelease-1>",
            "<Motion>",
            ]:
            self.canvas.tag_unbind(self.pic_cid, e)

    def canvas_xy(self, x, y):
        return self.canvas.canvasx(x), self.canvas.canvasy(y)

    def is_dragging(self):
        return self.drag_pic_cid is not None

    def start_drag_unit(self, event):
        if self.board.num_units_to_place() == 0:
            unit = self.unit
            self.raise_to_top()
            self.board.set_current_item_cid(self.pic_cid)
            if self.board.is_unit_drag_ok():
                cx, cy = self.canvas.coords(self.pic_cid)
                self.drag_pic_cid = self.canvas.create_image(
                    cx,
                    cy,
                    image=unit.xbm)
                self.canvas.focus(self.drag_pic_cid)
            
    def drag_unit(self, event):
        if self.is_dragging():
            x, y = self.canvas_xy(event.x, event.y)       
            self.canvas.coords(self.drag_pic_cid, x, y)

    def end_drag_unit(self, event):
        if self.is_dragging():
            self.canvas.delete(self.drag_pic_cid)
            self.drag_pic_cid = None

            x, y = self.compute_real_xy(self.canvas_xy(event.x, event.y))
            x0, y0, x1, y1 = self.canvas.bbox(self.pic_cid)
            if graphics.in_bbox(x, y, x0, y0, x1, y1):
                return

            if self.board.is_valid_move(self.unit, x, y):
                if self.board.is_new_destination(self.unit, x, y):
                    a = Action.MoveUnitNewDestAction(self.unit.name, x, y)
                else:
                    curx, cury = self.unit.last_move_xy()
                    a = Action.MoveUnitAction(self.unit.name, curx, cury, x, y)
                self.board.gameconf.ur_stack.push_action(a, self.board)

                self.check_move()

    def check_move(self):
        self.board.check_unit_move(self.unit)
        
    def raise_to_top(self):
        self.canvas.tag_raise(self.pic_cid)
                
    def snap_to_other_xy(self):
        return self.board.snap_to_other(self.unit)
        
    def show_unit_attrs(self, args):
        self.board.show_unit_editor(self.unit)
